/****************************************************************************
 * Copyright (C) 2025 Chenyz. All rights reserved.
 *
 * @file    TinyOS_Event.c
 *
 * @par     dependencies
 *          - TinyOS_Event.h (Event management definitions)
 *          - TinyOS_Task.h (Task management definitions)
 *          - TinyOS_Delay.h (Delay functionality)
 *
 * @author  Chenyz
 *
 * @brief   Event management implementation for TinyOS with features:
 *          - Event blocking and waiting mechanism
 *          - Task synchronization using events
 *          - Timeout support for event waiting
 *          - Multiple task wake-up from events
 *          - Event wait list management
 *          - Critical section protection for event operations
 *          - Integration with task scheduler for automatic rescheduling
 *
 * @version V1.0
 * @date    2025-09-16
 *
 * @note    Coding standard:
 *          - 4 spaces per indent level
 *          - Follow MISRA-C 2012 guidelines
 *          - Compiler compatibility: C99 and above
 *
 ****************************************************************************/

#include "TinyOS_Event.h"
#include "TinyOS_Task.h"
#include "TinyOS_Delay.h"

/**
 * @brief Initializes an event block structure
 * 
 * This function prepares an event block for use by setting its type and
 * initializing its wait list. Event blocks are used to manage tasks waiting
 * for specific events.
 * 
 * @param EventBlock Pointer to the event block structure to be initialized
 * @param EventType Type of the event to be assigned to the event block
 */
void TinyOS_EventBlockInit(
    TinyOS_EventBlockType* EventBlock,   
    TinyOS_EventType EventType
)
{
    EventBlock->EventType = EventType;
    TinyOS_ListInit(&EventBlock->WaitList);
}

/**
 * @brief Puts a task into waiting state for an event
 * 
 * This function suspends a task while it waits for an event to occur. The task
 * can optionally specify a timeout after which it will be automatically resumed.
 * 
 * @param EventBlock Pointer to the event block the task is waiting on
 * @param Task Pointer to the task to be put into waiting state
 * @param EventMsg Message associated with the event
 * @param Status Status flags to set for the waiting task
 * @param TimeoutTicks Maximum time to wait for the event (0 = wait indefinitely)
 */
void TinyOS_EventWait(
    TinyOS_EventBlockType*  EventBlock,
    TinyOS_TaskType*        Task,
    void*                   EventMsg,
    uint32_t                Status,
    uint32_t                TimeoutTicks
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();     

    /* Set task status and event information */
    Task->TaskStatus |= Status << 16;
    Task->TaskEventMsg = EventMsg;
    Task->TaskEventBlock = EventBlock;
    Task->TaskEventWaitResult = TinyOS_ErrorType_NoError;
    
    /* Remove task from ready list and add to event wait list */
    TinyOS_TaskSchedulerUnReady(Task);
    TinyOS_ListTailInsert(&(EventBlock->WaitList), &(Task->TaskListNode));
    
    /* Set timeout if specified */
    if(TimeoutTicks)
    {
        TinyOS_TaskDelayTimeWait(Task, TimeoutTicks);
    }

    TinyOS_TaskExitCritical(Stauts);   
}

/**
 * @brief Wakes up the first task waiting on an event
 * 
 * This function wakes up the first task in the event's wait list and provides
 * it with the event result. The task is made ready for scheduling.
 * 
 * @param EventBlock Pointer to the event block
 * @param EventMsg Message to pass to the awakened task
 * @param Result Result code to set for the awakened task
 * @return TinyOS_TaskType* Pointer to the awakened task, or NULL if no task was waiting
 */
TinyOS_TaskType* TinyOS_EventWake(
    TinyOS_EventBlockType*  EventBlock,
    void*                   EventMsg,
    uint32_t                Result
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();  
    
    TinyOS_NodeType* TempNode = TinyOS_ListHeadDelete(&(EventBlock->WaitList));
    TinyOS_TaskType* TempTaskHandler = (TinyOS_TaskType*)0;
    
    if(TempNode != (TinyOS_NodeType*)0)
    {
        TempTaskHandler = (TinyOS_TaskType*)TINYOS_NODE_PARENT(TempNode, TinyOS_TaskType, TaskListNode);
        TempTaskHandler->TaskEventMsg = EventMsg;
        TempTaskHandler->TaskEventBlock = (TinyOS_EventBlockType*)0;
        TempTaskHandler->TaskEventWaitResult = Result;
        TempTaskHandler->TaskStatus &= ~TINYOS_TASK_WAIT_MASK;
        
        /* Handle timeout if task was also waiting with timeout */
        if(TempTaskHandler->TaskDelayTicks != 0)
        {
            TinyOS_TaskDelayTimeWake(TempTaskHandler);
        }
        
        /* Make task ready for scheduling */
        TinyOS_TaskSchedulerReady(TempTaskHandler);
    }

    TinyOS_TaskExitCritical(Stauts);   
    return TempTaskHandler;
}

/**
 * @brief Wakes up a specific task waiting on an event
 * 
 * This function wakes up a specified task from the event's wait list and provides
 * it with the event result. The task is made ready for scheduling. This is useful
 * for selectively waking specific tasks rather than the first one in the queue.
 * 
 * @param EventBlock Pointer to the event block
 * @param TaskHandler Pointer to the specific task to be woken up
 * @param EventMsg Message to pass to the awakened task
 * @param Result Result code to set for the awakened task
 */
void TinyOS_EventWakeTask(
    TinyOS_EventBlockType*  EventBlock,
    TinyOS_TaskType*        TaskHandler,
    void*                   EventMsg,
    uint32_t                Result
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();  

    /* Remove the specific task from the event wait list */
    TinyOS_ListDeleteNode(&EventBlock->WaitList, &TaskHandler->TaskListNode);
    
    /* Clear task's event waiting status and set result */
    TaskHandler->TaskEventMsg = EventMsg;
    TaskHandler->TaskEventBlock = (TinyOS_EventBlockType*)0;
    TaskHandler->TaskEventWaitResult = Result;
    TaskHandler->TaskStatus &= ~TINYOS_TASK_WAIT_MASK;
    
    /* Handle timeout if task was also waiting with timeout */
    if(TaskHandler->TaskDelayTicks != 0)
    {
        TinyOS_TaskDelayTimeWake(TaskHandler);
    }
    
    /* Make task ready for scheduling */
    TinyOS_TaskSchedulerReady(TaskHandler);

    TinyOS_TaskExitCritical(Stauts);   
}

/**
 * @brief Removes a specific task from event waiting
 * 
 * This function removes a task from an event's wait list without waking up
 * other tasks. Used for targeted task management.
 * 
 * @param Task Pointer to the task to be removed from waiting
 * @param EventMsg Message to set for the removed task
 * @param Result Result code to set for the removed task
 */
void TinyOS_EventRemoveTask(
    TinyOS_TaskType*        Task,
    void*                   EventMsg,
    uint32_t                Result
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();     
    
    /* Remove task from event wait list */
    TinyOS_ListDeleteNode(
        &(Task->TaskEventBlock->WaitList), 
        &(Task->TaskListNode)
    );

    /* Clear task's event waiting status */
    Task->TaskEventMsg = EventMsg;
    Task->TaskEventBlock = (TinyOS_EventBlockType*)0;
    Task->TaskEventWaitResult = Result;
    Task->TaskStatus &= ~TINYOS_TASK_WAIT_MASK;

    TinyOS_TaskExitCritical(Stauts);   
}    
        
/**
 * @brief Wakes up all tasks waiting on an event
 * 
 * This function wakes up all tasks currently waiting on the specified event
 * and makes them ready for scheduling.
 * 
 * @param EventBlock Pointer to the event block
 * @param EventMsg Message to pass to all awakened tasks
 * @param Result Result code to set for all awakened tasks
 * @return uint32_t Number of tasks that were awakened
 */
uint32_t TinyOS_EventRemoveAll(
    TinyOS_EventBlockType*  EventBlock,
    void*                   EventMsg,
    uint32_t                Result
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();     

    TinyOS_TaskType* TempTaskHandler;
    TinyOS_NodeType* TempNode;
    uint32_t TaskWaitCount = TinyOS_ListNodeCount(&(EventBlock->WaitList));
    
    /* Process all tasks in the wait list */
    while((TempNode = TinyOS_ListHeadDelete(&(EventBlock->WaitList))) != (TinyOS_NodeType*)0)
    {
        TempTaskHandler = (TinyOS_TaskType*)TINYOS_NODE_PARENT(TempNode, TinyOS_TaskType, TaskListNode);
       
        /* Clear task's event waiting status */
        TempTaskHandler->TaskEventMsg = EventMsg;
        TempTaskHandler->TaskEventBlock = (TinyOS_EventBlockType*)0;
        TempTaskHandler->TaskEventWaitResult = Result;
        TempTaskHandler->TaskStatus &= ~TINYOS_TASK_WAIT_MASK;     

        /* Handle timeout if task was also waiting with timeout */
        if(TempTaskHandler->TaskDelayTicks != 0)
        {
            TinyOS_TaskDelayTimeWake(TempTaskHandler);
        }
        
        /* Make task ready for scheduling */
        TinyOS_TaskSchedulerReady(TempTaskHandler);
    }
    
    TinyOS_TaskExitCritical(Stauts);  
    return TaskWaitCount;
} 

/**
 * @brief Returns the number of tasks waiting on an event
 * 
 * This function provides a count of how many tasks are currently waiting
 * on the specified event block.
 * 
 * @param EventBlock Pointer to the event block
 * @return uint32_t Number of tasks waiting on the event
 */
uint32_t TinyOS_EventWaitCount(TinyOS_EventBlockType* EventBlock)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();     

    uint32_t TaskWaitCount = TinyOS_ListNodeCount(&(EventBlock->WaitList));
    
    TinyOS_TaskExitCritical(Stauts);    
    return TaskWaitCount;
}
